package com.cardone.persistent.support;

import com.cardone.common.dao.*;
import com.cardone.common.dto.*;
import com.cardone.common.po.*;
import com.cardone.context.*;
import com.cardone.persistent.builder.*;
import com.google.common.collect.*;
import lombok.*;
import org.apache.commons.collections.*;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 简易jdbc dao
 *
 * @author yaohaitao
 */
@Setter
public abstract class SimpleJdbcDao<D extends PoBase> implements SimpleDao<D> {
    /**
     * 代码名称集合
     */
    protected String[] codeNames;

    protected String deleteByCode;

    protected String deleteByIds;

    protected String findByCode;

    protected String findById;

    protected String findByLikeCode;

    /**
     * 标识名称集合
     */
    protected String[] idNames;

    protected String insertByCode;

    protected String insertByNotExistsCode;

    protected String readByCode;

    protected String readByLikeCode;

    protected String updateByIds;

    protected String updateByCode;
    /**
     * 更新名称集合
     */
    protected String[] updateNames;

    /**
     * 构造
     */
    public SimpleJdbcDao() {
    }

    /**
     * 构造
     *
     * @param root 根目录
     */
    public SimpleJdbcDao(String root) {
        this.deleteByCode = root + "deleteByCode";
        this.deleteByIds = root + "deleteByIds";
        this.findByCode = root + "findByCode";
        this.findById = root + "findById";
        this.findByLikeCode = root + "findByLikeCode";
        this.insertByCode = root + "insertByCode";
        this.insertByNotExistsCode = root + "insertByNotExistsCode";
        this.readByCode = root + "readByCode";
        this.readByLikeCode = root + "readByLikeCode";
        this.updateByCode = root + "updateByCode";
    }

    @Override
    public <P> P saveByIdOrCode(final Class<P> mappedClass, final D save, String... selectNames) {
        if (ArrayUtils.isEmpty(this.codeNames) && this.isBlankById(save)) {
            this.insertByCode(save);

            return this.findByCodeOrId(mappedClass, save, selectNames);
        }

        final int updateCount = this.updateByCode(save);

        if (updateCount > 1) {
            throw new DictionaryException("更新到多个数据").setTypeCode("updateBy").setCode("multiple");
        }

        if (updateCount < 1) {
            this.insertByNotExistsCode(save);
        }

        return this.findByCodeOrId(mappedClass, save, selectNames);
    }

    @Override
    public Map<String, Object> saveByIdOrCode(D save, String... selectNames) {
        if (ArrayUtils.isEmpty(this.codeNames) && this.isBlankById(save)) {
            this.insertByCode(save);

            return this.findByCodeOrId(save, selectNames);
        }

        final int updateCount = this.updateByCode(save);

        if (updateCount > 1) {
            throw new DictionaryException("更新到多个数据").setTypeCode("updateBy").setCode("multiple");
        }

        if (updateCount < 1) {
            this.insertByNotExistsCode(save);
        }

        return this.findByCodeOrId(save, selectNames);
    }

    @Override
    public <P> P saveByIdOrCode(Class<P> mappedClass, Map<String, Object> saveMap, String... selectNames) {
        if (ArrayUtils.isEmpty(this.codeNames) && this.isBlankById(saveMap)) {
            this.insertByCode(saveMap);

            return this.findByCodeOrId(mappedClass, saveMap, selectNames);
        }

        final int updateCount = this.updateByCode(saveMap);

        if (updateCount > 1) {
            throw new DictionaryException("更新到多个数据").setTypeCode("updateBy").setCode("multiple");
        }

        if (updateCount < 1) {
            this.insertByNotExistsCode(saveMap);
        }

        return this.findByCodeOrId(mappedClass, saveMap, selectNames);
    }

    @Override
    public Map<String, Object> saveByIdOrCode(Map<String, Object> saveMap, String... selectNames) {
        if (ArrayUtils.isEmpty(this.codeNames) && this.isBlankById(saveMap)) {
            this.insertByCode(saveMap);

            return this.findByCodeOrId(saveMap, selectNames);
        }

        final int updateCount = this.updateByCode(saveMap);

        if (updateCount > 1) {
            throw new DictionaryException("更新到多个数据").setTypeCode("updateBy").setCode("multiple");
        }

        if (updateCount < 1) {
            this.insertByNotExistsCode(saveMap);
        }

        return this.findByCodeOrId(saveMap, selectNames);
    }

    @Override
    public int insertByCode(final D insert) {
        return this.insertBy(this.insertByCode, insert);
    }

    @Override
    public int insertByCode(Map<String, Object> insertMap) {
        return this.insertBy(this.insertByCode, insertMap);
    }

    /**
     * 插入
     *
     * @param insertList 对象集合
     * @return 影响行数
     */
    @Override
    public int[] insertByCode(final List<D> insertList) {
        return this.insertBy(this.insertByCode, insertList);
    }

    protected int[] insertBy(final String insertId, final List<D> insertList) {
        if (CollectionUtils.isEmpty(insertList)) {
            return ArrayUtils.EMPTY_INT_ARRAY;
        }

        int[] insertCounts = new int[insertList.size()];

        for (int i = 0; i < insertList.size(); i++) {
            insertCounts[i] = this.insertBy(insertId, insertList.get(i));
        }

        return insertCounts;
    }

    @Override
    public int insertByNotExistsCode(final D insert) {
        final Model model = ModelUtils.newModel(insert.getAttrs());

        String[] whereAndEqProperties;

        if (this.isBlankById(insert)) {
            this.setId(insert);

            whereAndEqProperties = this.codeNames;
        } else {
            whereAndEqProperties = this.idNames;
        }

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(insert, whereAndEqProperties));
        }

        ModelUtils.put(model, new ModelArgs(Model.Keys.insert.stringValue(), insert));

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(this.insertByNotExistsCode, model);
    }

    @Override
    public int insertByNotExistsCode(Map<String, Object> insertMap) {
        final Model model = ModelUtils.newModel();

        String[] whereAndEqProperties;

        if (this.isBlankById(insertMap)) {
            this.setId(insertMap);

            whereAndEqProperties = this.codeNames;
        } else {
            whereAndEqProperties = this.idNames;
        }

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(insertMap, whereAndEqProperties));
        }

        ModelUtils.put(model, new ModelArgs(Model.Keys.insert.stringValue(), insertMap));

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(this.insertByNotExistsCode, model);
    }

    @Override
    public int insertByNotExistsCode(final Map<String, Object> insertMap, final Map<String, Object> whereAndEqMap) {
        if (this.isBlankById(insertMap)) {
            this.setId(insertMap);
        }

        final Model model = ModelUtils.newModel(new ModelArgs(Model.Keys.insert.stringValue(), insertMap), new ModelArgs(whereAndEqMap));

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(this.insertByNotExistsCode, model);
    }

    @Override
    public int[] insertByNotExistsCode(final List<D> insertList) {
        if (CollectionUtils.isEmpty(insertList)) {
            return ArrayUtils.EMPTY_INT_ARRAY;
        }

        int[] insertCounts = new int[insertList.size()];

        for (int i = 0; i < insertList.size(); i++) {
            insertCounts[i] = this.insertByNotExistsCode(insertList.get(i));
        }

        return insertCounts;
    }

    @Override
    public int deleteByIds(final D delete) {
        return this.deleteByIds(delete.getIds());
    }

    @Override
    public int updateByIds(String ids) {
        final Map<String, Object> model = Maps.newHashMap();

        model.put(Attributes.ids.name(), ids);

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(this.updateByIds, model);
    }

    @Override
    public int updateByIds(D delete) {
        return this.updateByIds(delete.getIds());
    }

    @Override
    public int deleteByIds(String ids) {
        final Map<String, Object> model = Maps.newHashMap();

        model.put(Attributes.ids.name(), ids);

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(this.deleteByIds, model);
    }

    @Override
    public int deleteByCode(final D delete, final String... whereAndEqProperties) {
        return this.deleteBy(this.deleteByCode, delete, whereAndEqProperties);
    }

    @Override
    public int[] deleteByCode(List<D> deleteList, String... whereAndEqProperties) {
        return this.deleteBy(this.deleteByCode, deleteList, whereAndEqProperties);
    }

    protected int[] deleteBy(final String deleteId, final List<D> deleteList, final String... whereAndEqProperties) {
        if (CollectionUtils.isEmpty(deleteList)) {
            return ArrayUtils.EMPTY_INT_ARRAY;
        }

        int[] deleteCounts = new int[deleteList.size()];

        for (int i = 0; i < deleteList.size(); i++) {
            deleteCounts[i] = this.deleteBy(deleteId, deleteList.get(i), whereAndEqProperties);
        }

        return deleteCounts;
    }

    @Override
    public int deleteByCode(Map<String, Object> whereAndEqMap) {
        return this.updateBy(this.deleteByCode, whereAndEqMap);
    }

    @Override
    public int[] deleteByCode(List<Map<String, Object>> whereAndEqMapList) {
        return this.deleteBy(this.deleteByCode, whereAndEqMapList);
    }

    @Override
    public int updateByCode(D update, String... updateNames) {
        return this.updateBy(this.updateByCode, update, updateNames);
    }

    @Override
    public int updateByCode(D update) {
        return this.updateBy(this.updateByCode, update);
    }

    @Override
    public int updateByCode(Map<String, Object> updateMap, String... updateNames) {
        return this.updateBy(this.updateByCode, updateMap, updateNames);
    }

    @Override
    public int updateByCode(Map<String, Object> updateMap) {
        return this.updateBy(this.updateByCode, updateMap);
    }

    @Override
    public int[] updateByCode(List<D> updateList, String... updateNames) {
        return this.updateBy(this.updateByCode, updateList, updateNames);
    }

    @Override
    public int[] updateByCode(List<D> updateList, String[] whereAndEqProperties, String... updateNames) {
        return this.updateBy(this.updateByCode, updateList, whereAndEqProperties, updateNames);
    }

    @Override
    public int updateByCode(D update, String[] whereAndEqProperties, String... updateNames) {
        return this.updateBy(this.updateByCode, update, whereAndEqProperties, updateNames);
    }

    @Override
    public int updateByCode(Map<String, Object> updateMap, String[] whereAndEqProperties, String... updateNames) {
        return this.updateBy(this.updateByCode, updateMap, whereAndEqProperties, updateNames);
    }

    @Override
    public int updateByCode(Map<String, Object> whereAndEqMap, Map<String, Object> updateMap) {
        return this.updateBy(this.updateByCode, whereAndEqMap, updateMap);
    }

    @Override
    public Integer readByCodeNqIdForCount(final D read) {
        final Model model = ModelUtils.newModel(read.getAttrs());

        ModelUtils.put(model, new ModelArgs(read, this.codeNames));

        if (!this.isBlankById(read)) {
            ModelUtils.put(model, new ModelArgs(Model.Keys.whereAndNq.stringValue(), read, this.idNames));
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, this.readByCode, model);
    }

    @Override
    public <R> R readByCode(Class<R> requiredType, String objectId, D read, String... whereAndEqProperties) {
        final Model model = ModelUtils.newModel(new ModelArgs(read, whereAndEqProperties));

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(requiredType, this.readByCode, objectId, model);
    }

    @Override
    public <R> R readByCode(Class<R> requiredType, String objectId, Map<String, Object> whereAndEqMap) {
        final Model model = ModelUtils.newModel(whereAndEqMap, new ModelArgs(whereAndEqMap));

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(requiredType, this.readByCode, objectId, model);
    }

    @Override
    public Integer readByCodeNqIdForCount(Map<String, Object> readMap) {
        final Model model = ModelUtils.newModel();

        if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(this.codeNames)) {
            ModelUtils.put(model, new ModelArgs(readMap, this.codeNames));
        }

        if (!this.isBlankById(readMap)) {
            if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(this.idNames)) {
                ModelUtils.put(model, new ModelArgs(Model.Keys.whereAndNq.stringValue(), readMap, this.idNames));
            }
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, this.readByCode, model);
    }

    @Override
    public Integer readByLikeCode(D read, String... whereAndEqProperties) {
        return this.readForInteger(this.readByLikeCode, read, null, whereAndEqProperties);
    }

    @Override
    public Integer readByLikeCode(Map<String, Object> readMap) {
        return this.readForInteger(this.readByLikeCode, null, readMap);
    }

    @Override
    public <P> P findById(final Class<P> mappedClass, final D find, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        ModelUtils.put(model, new ModelArgs(find, this.idNames).setIsSimple(true));

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, this.findById, model);
    }

    @Override
    public Map<String, Object> findById(final D find, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        ModelUtils.put(model, new ModelArgs(find, this.idNames).setIsSimple(true));

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(this.findById, model);
    }

    @Override
    public <P> P findById(Class<P> mappedClass, Map<String, Object> findMap, String... selectNames) {
        final Model model = ModelUtils.newModel(findMap).putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, this.findById, model);
    }

    @Override
    public Map<String, Object> findById(Map<String, Object> findMap, String... selectNames) {
        final Model model = ModelUtils.newModel(findMap).putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(this.findById, model);
    }

    @Override
    public <P> P findByCode(final Class<P> mappedClass, final D find, final String[] whereAndEqProperties, String... selectNames) {
        return this.findBy(mappedClass, this.findByCode, find, whereAndEqProperties, selectNames);
    }

    protected <P> P findBy(final Class<P> mappedClass, final String findId, final D find, final String[] whereAndEqProperties, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        ModelUtils.put(model, new ModelArgs(find).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(find, whereAndEqProperties));
        }

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, findId, model);
    }

    @Override
    public <P> P findByCode(Class<P> mappedClass, Map<String, Object> whereAndEqMap, String... selectNames) {
        return this.findBy(mappedClass, this.findByCode, whereAndEqMap, selectNames);
    }

    protected <P> P findBy(final Class<P> mappedClass, final String findId, Map<String, Object> whereAndEqMap, String... selectNames) {
        final Model model = ModelUtils.newModel(whereAndEqMap, new ModelArgs(whereAndEqMap));

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, findId, model);
    }

    @Override
    public Map<String, Object> findByCode(Map<String, Object> whereAndEqMap, String... selectNames) {
        return this.findBy(this.findByCode, whereAndEqMap, selectNames);
    }

    @Override
    public <P> P findByCode(Class<P> mappedClass, D find, String... whereAndEqProperties) {
        return this.findBy(mappedClass, this.findByCode, find, whereAndEqProperties);
    }

    @Override
    public Map<String, Object> findByCode(D find, String[] whereAndEqProperties, String... selectNames) {
        return this.findBy(this.findByCode, find, whereAndEqProperties, selectNames);
    }

    @Override
    public Map<String, Object> findByCode(D find, String... whereAndEqProperties) {
        return this.findBy(this.findByCode, find, whereAndEqProperties);
    }

    @Override
    public <P> P findByCodeOrId(final Class<P> mappedClass, final D find, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        final String[] whereAndEqProperties = this.isBlankById(find) ? this.codeNames : this.idNames;

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(find, whereAndEqProperties));
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, this.findByCode, model);
    }

    @Override
    public Map<String, Object> findByCodeOrId(D find, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        final String[] whereAndEqProperties = this.isBlankById(find) ? this.codeNames : this.idNames;

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(find, whereAndEqProperties));
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(this.findByCode, model);
    }

    @Override
    public <P> P findByCodeOrId(Class<P> mappedClass, Map<String, Object> findMap, String... selectNames) {
        final Model model = ModelUtils.newModel();

        final String[] whereAndEqProperties = this.isBlankById(findMap) ? this.codeNames : this.idNames;

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(findMap, whereAndEqProperties));
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(mappedClass, this.findByCode, model);
    }

    @Override
    public Map<String, Object> findByCodeOrId(Map<String, Object> findMap, String... selectNames) {
        final Model model = ModelUtils.newModel();

        final String[] whereAndEqProperties = this.isBlankById(findMap) ? this.codeNames : this.idNames;

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(findMap, whereAndEqProperties));
        }

        model.putTrue(Model.Keys.whereAndBetween.stringValue(), Attributes.sysdate.name());

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(this.findByCode, model);
    }

    @Override
    public <P> List<P> findListByLikeCode(final Class<P> mappedClass, final D findList, String[] whereAndEqProperties, String... selectNames) {
        return this.findListBy(mappedClass, this.findByLikeCode, findList, whereAndEqProperties, selectNames);
    }

    @Override
    public <P> List<P> findListByLikeCode(Class<P> mappedClass, D findList, String... whereAndEqProperties) {
        return this.findListBy(mappedClass, this.findByLikeCode, findList, whereAndEqProperties);
    }

    @Override
    public List<Map<String, Object>> findListByLikeCode(D findList, String[] whereAndEqProperties, String... selectNames) {
        return this.findListBy(this.findByLikeCode, findList, whereAndEqProperties, selectNames);
    }

    @Override
    public List<Map<String, Object>> findListByLikeCode(D findList, String... whereAndEqProperties) {
        return this.findListBy(this.findByLikeCode, findList, whereAndEqProperties);
    }

    @Override
    public <P> List<P> findListByLikeCode(Class<P> mappedClass, Map<String, Object> findListMap, String... selectNames) {
        return this.findListBy(mappedClass, this.findByLikeCode, findListMap, selectNames);
    }

    @Override
    public List<Map<String, Object>> findListByLikeCode(Map<String, Object> findListMap, String... selectNames) {
        return this.findListBy(this.findByLikeCode, findListMap, selectNames);
    }

    @Override
    public <P> List<P> findListByCode(final Class<P> mappedClass, final D findList, final String[] whereAndEqProperties, String... selectNames) {
        return this.findListBy(mappedClass, this.findByCode, findList, whereAndEqProperties, selectNames);
    }

    @Override
    public <P> List<P> findListByCode(Class<P> mappedClass, D findList, String... whereAndEqProperties) {
        return this.findListBy(mappedClass, this.findByCode, findList, whereAndEqProperties);
    }

    @Override
    public <P> List<P> findListByCode(Class<P> mappedClass, Map<String, Object> findListMap, String... selectNames) {
        return this.findListBy(mappedClass, this.findByCode, findListMap, selectNames);
    }

    @Override
    public List<Map<String, Object>> findListByCode(D findList, String[] whereAndEqProperties, String... selectNames) {
        return this.findListBy(this.findByCode, findList, whereAndEqProperties, selectNames);
    }

    @Override
    public List<Map<String, Object>> findListByCode(D findList, String... whereAndEqProperties) {
        return this.findListBy(this.findByCode, findList, whereAndEqProperties);
    }

    @Override
    public List<Map<String, Object>> findListByCode(Map<String, Object> findListMap, String... selectNames) {
        return this.findListBy(this.findByCode, findListMap, selectNames);
    }

    @Override
    public <P> List<P> findList(final Class<P> mappedClass, String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(mappedClass, this.findByCode, model);
    }

    @Override
    public List<Map<String, Object>> findList(String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(this.findByCode, model);
    }

    @Override
    public <P> PaginationDto<P> paginationByLikeCode(final Class<P> mappedClass, final D pagination) {
        return this.paginationBy(mappedClass, this.readByLikeCode, this.findByLikeCode, pagination);
    }

    protected <P> PaginationDto<P> paginationBy(final Class<P> mappedClass, final String readId, final String findId, final D pagination) {
        final Model model = ModelUtils.newModel(pagination.getAttrs());

        ModelUtils.put(model, new ModelArgs(pagination).setIsSimple(true));

        return ContextHolder.getBean(JdbcTemplateSupport.class).pagination(mappedClass, new PaginationArgs(readId, findId, pagination), model);
    }

    @Override
    public PaginationDto<Map<String, Object>> paginationByLikeCode(D pagination) {
        return this.paginationBy(this.readByLikeCode, this.findByLikeCode, pagination);
    }

    protected PaginationDto<Map<String, Object>> paginationBy(final String readId, final String findId, final D pagination) {
        final Model model = ModelUtils.newModel(pagination.getAttrs());

        ModelUtils.put(model, new ModelArgs(pagination).setIsSimple(true));

        return ContextHolder.getBean(JdbcTemplateSupport.class).pagination(new PaginationArgs(readId, findId, pagination), model);
    }

    @Override
    public <P> PaginationDto<P> paginationByLikeCode(Class<P> mappedClass, Map<String, Object> paginationMap) {
        return this.paginationBy(mappedClass, this.readByLikeCode, this.findByLikeCode, paginationMap);
    }

    protected <P> PaginationDto<P> paginationBy(final Class<P> mappedClass, final String readId, final String findId, final Map<String, Object> paginationMap) {
        return ContextHolder.getBean(JdbcTemplateSupport.class).pagination(mappedClass, new PaginationArgs(readId, findId, paginationMap), paginationMap);
    }

    @Override
    public PaginationDto<Map<String, Object>> paginationByLikeCode(Map<String, Object> paginationMap) {
        return this.paginationBy(this.readByLikeCode, this.findByLikeCode, paginationMap);
    }

    protected PaginationDto<Map<String, Object>> paginationBy(final String readId, final String findId, final Map<String, Object> paginationMap) {
        return ContextHolder.getBean(JdbcTemplateSupport.class).pagination(new PaginationArgs(readId, findId, paginationMap), paginationMap);
    }

    protected List<Map<String, Object>> findListBy(final String findId, Map<String, Object> findListMap, String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        if (MapUtils.isEmpty(findListMap)) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).findList(findId, model);
        }

        ModelUtils.put(model, findListMap);

        ModelUtils.put(model, new ModelArgs(findListMap));

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(findId, model);
    }

    protected <P> List<P> findListBy(final Class<P> mappedClass, final String findId, Map<String, Object> whereAndEqMap, String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        if (MapUtils.isEmpty(whereAndEqMap)) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).findList(mappedClass, findId, model);
        }

        ModelUtils.put(model, whereAndEqMap);

        ModelUtils.put(model, new ModelArgs(whereAndEqMap));

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(mappedClass, findId, model);
    }

    protected List<Map<String, Object>> findListBy(final String findId, final D findList, final String[] whereAndEqProperties, String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        if (findList == null) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).findList(findId, model);
        }

        ModelUtils.put(model, findList.getAttrs());

        ModelUtils.put(model, new ModelArgs(findList).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(findList, whereAndEqProperties));
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(findId, model);
    }

    protected <P> List<P> findListBy(final Class<P> mappedClass, final String findId, final D findList, final String[] whereAndEqProperties, String... selectNames) {
        final Model model = ModelUtils.newModel().putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        if (findList == null) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).findList(mappedClass, findId, model);
        }

        ModelUtils.put(model, findList.getAttrs());

        ModelUtils.put(model, new ModelArgs(findList).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(findList, whereAndEqProperties));
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).findList(mappedClass, findId, model);
    }

    protected Map<String, Object> findBy(final String findId, final D find, final String[] whereAndEqProperties, String... selectNames) {
        final Model model = ModelUtils.newModel(find.getAttrs());

        ModelUtils.put(model, new ModelArgs(find).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(find, whereAndEqProperties));
        }

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(findId, model);
    }

    protected Map<String, Object> findBy(final String findId, Map<String, Object> whereAndEqMap, String... selectNames) {
        final Model model = ModelUtils.newModel(whereAndEqMap, new ModelArgs(whereAndEqMap));

        model.putTrueExtend(Model.Keys.select.stringValue(), selectNames);

        return ContextHolder.getBean(JdbcTemplateSupport.class).find(findId, model);
    }

    protected Integer readForInteger(final String readId, String objectId, java.util.Map<String, Object> readMap) {
        if (MapUtils.isEmpty(readMap)) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, readId);
        }

        final Model model = ModelUtils.newModel(readMap, new ModelArgs(readMap));

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, readId, objectId, model);
    }

    protected Integer readForInteger(final String readId, final D read, String objectId, final String... whereAndEqProperties) {
        if (read == null) {
            return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, readId);
        }

        final Model model = ModelUtils.newModel(read.getAttrs());

        ModelUtils.put(model, new ModelArgs(read).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(read, whereAndEqProperties));
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).read(Integer.class, readId, objectId, model);
    }

    protected int updateBy(final String updateId, Map<String, Object> whereAndEqMap, final Map<String, Object> updateMap) {
        final Model model = ModelUtils.newModel(new ModelArgs(Model.Keys.update.stringValue(), updateMap), new ModelArgs(whereAndEqMap));

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(updateId, model);
    }

    protected int[] updateBy(final String updateId, final List<D> updateList, final String... updateNames) {
        return updateBy(updateId, updateList, null, updateNames);
    }

    protected int[] updateBy(final String updateId, final List<D> updateList, final String[] whereAndEqProperties, final String... updateNames) {
        if (CollectionUtils.isEmpty(updateList)) {
            return ArrayUtils.EMPTY_INT_ARRAY;
        }

        int[] updateCounts = new int[updateList.size()];

        for (int i = 0, k = updateList.size(); i < k; i++) {
            updateCounts[i] = this.updateBy(updateId, updateList.get(i), whereAndEqProperties, updateNames);
        }

        return updateCounts;
    }

    protected int updateBy(final String updateId, final Map<String, Object> updateMap, final String... updateNames) {
        final String[] whereAndEqProperties = this.isBlankById(updateMap) ? this.codeNames : this.idNames;

        return this.updateBy(updateId, updateMap, whereAndEqProperties, updateNames);
    }

    protected int updateBy(final String updateId, final D update, final String... updateNames) {
        final String[] whereAndEqProperties = this.isBlankById(update) ? this.codeNames : this.idNames;

        return this.updateBy(updateId, update, whereAndEqProperties, updateNames);
    }

    protected int[] deleteBy(final String deleteId, final List<Map<String, Object>> deleteMapList) {
        if (CollectionUtils.isEmpty(deleteMapList)) {
            return ArrayUtils.EMPTY_INT_ARRAY;
        }

        int[] deleteCounts = new int[deleteMapList.size()];

        for (int i = 0; i < deleteMapList.size(); i++) {
            deleteCounts[i] = this.updateBy(deleteId, deleteMapList.get(i));
        }

        return deleteCounts;
    }

    protected int deleteBy(final String deleteId, final D delete, final String... whereAndEqProperties) {
        final Model model = ModelUtils.newModel(delete.getAttrs());

        ModelUtils.put(model, new ModelArgs(delete).setIsSimple(true));

        if (ArrayUtils.isNotEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(delete, whereAndEqProperties));
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(deleteId, model);
    }

    /**
     * 标识是否为空值
     *
     * @param map
     * @return
     */
    protected boolean isBlankById(final Map<String, Object> map) {
        String id = MapUtils.getString(map, Attributes.id.name());

        if (StringUtils.isBlank(id)) {
            return true;
        }

        return false;
    }

    protected int insertBy(final String insertId, final Map<String, Object> insertMap) {
        if (this.isBlankById(insertMap)) {
            this.setId(insertMap);
        }

        final Model model = ModelUtils.newModel(new ModelArgs(Model.Keys.insert.stringValue(), insertMap));

        ModelUtils.put(model, insertMap);

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(insertId, model);
    }

    protected int updateBy(final String updateId, final Map<String, Object> updateMap) {
        final String[] whereAndEqProperties = this.isBlankById(updateMap) ? this.codeNames : this.idNames;

        return this.updateBy(updateId, updateMap, whereAndEqProperties, this.updateNames);
    }

    /**
     * 设置标
     *
     * @param map
     */
    protected void setId(final Map<String, Object> map) {
        map.put(Attributes.id.name(), UUID.randomUUID().toString());
    }

    protected int updateBy(final String updateId, final Map<String, Object> updateMap, final String[] whereAndEqProperties, final String... updateNames) {
        final Model model = ModelUtils.newModel();

        if (org.apache.commons.lang3.ArrayUtils.isEmpty(updateNames) && org.apache.commons.lang3.ArrayUtils.isEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, updateMap);
        } else {
            if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(updateNames)) {
                ModelUtils.put(model, new ModelArgs(Model.Keys.update.stringValue(), updateMap, updateNames));
            }

            if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(whereAndEqProperties)) {
                ModelUtils.put(model, new ModelArgs(updateMap, whereAndEqProperties));
            }
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(updateId, model);
    }

    /**
     * 标识是否为空值
     *
     * @param dto
     * @return
     */
    protected abstract boolean isBlankById(final D dto);

    protected int insertBy(final String insertId, final D insert) {
        final Model model = ModelUtils.newModel(insert.getAttrs());

        if (this.isBlankById(insert)) {
            this.setId(insert);
        }

        ModelUtils.put(model, new ModelArgs(Model.Keys.insert.stringValue(), insert));

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(insertId, model);
    }

    protected int updateBy(final String updateId, final D update) {
        final String[] whereAndEqProperties = this.isBlankById(update) ? this.codeNames : this.idNames;

        return this.updateBy(updateId, update, whereAndEqProperties, this.updateNames);
    }

    /**
     * 设置标
     *
     * @param dto
     */
    protected abstract void setId(final D dto);

    protected int updateBy(final String updateId, final D update, final String[] whereAndEqProperties, final String... updateNames) {
        final Model model = ModelUtils.newModel(update.getAttrs());

        if (org.apache.commons.lang3.ArrayUtils.isEmpty(updateNames) && org.apache.commons.lang3.ArrayUtils.isEmpty(whereAndEqProperties)) {
            ModelUtils.put(model, new ModelArgs(update).setIsSimple(true));
        } else {
            if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(updateNames)) {
                ModelUtils.put(model, new ModelArgs(Model.Keys.update.stringValue(), update, updateNames));
            }

            if (org.apache.commons.lang3.ArrayUtils.isNotEmpty(whereAndEqProperties)) {
                ModelUtils.put(model, new ModelArgs(update, whereAndEqProperties));
            }
        }

        return ContextHolder.getBean(JdbcTemplateSupport.class).update(updateId, model);
    }
}